package org.thanos.baseline.utils;

import lombok.extern.slf4j.Slf4j;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.util.Date;


@Slf4j
public class TimePointUtils {

    private TimePointUtils() {
    }

    /**
     * 获得timePoint所指定的时间点所在周的第一天的第一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在的周的第一天的第一秒
     */
    public static LocalDateTime firstSecondOfTheWeek(final LocalDateTime timePoint) {
        return firstSecondOfTheDay(
                timePoint.minusDays(
                        (timePoint.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue())));
    }

    /**
     * 获得timePoint所指定的时间点所在周的最后一天的最后一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在周的最后一天的最后一秒
     */
    public static LocalDateTime lastSecondOfTheWeek(final LocalDateTime timePoint) {
        return lastSecondOfTheDay(
                timePoint.plusDays(
                        (DayOfWeek.SUNDAY.getValue() - timePoint.getDayOfWeek().getValue())));
    }

    /**
     * 获得timePoint所指定的时间点所在月的第一天的第一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在月的第一天的第一秒
     */
    public static LocalDateTime firstSecondOfTheMonth(final LocalDateTime timePoint) {
        return firstSecondOfTheDay(timePoint.minusDays((timePoint.getDayOfMonth() - 1)));
    }

    /**
     * 获得timePoint所指定的时间点所在小时的第一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在小时的第一秒
     */
    public static LocalDateTime firstSecondOfTheHour(final LocalDateTime timePoint) {
        return LocalDateTime.of(timePoint.getYear(), timePoint.getMonthValue(), timePoint.getDayOfMonth(),
                timePoint.getHour(), 0, 0);
    }

    /**
     * 获得timePoint所指定的时间点所在小时的第一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在小时的第一秒
     */
    public static LocalDateTime lastSecondOfTheHour(final LocalDateTime timePoint) {
        return LocalDateTime.of(timePoint.getYear(), timePoint.getMonthValue(), timePoint.getDayOfMonth(),
                timePoint.getHour(), 59, 59);
    }

    /**
     * 获得本月第一天的第一秒
     *
     * @return 本月第一天的第一秒
     */
    public static LocalDateTime firstSecondOfThisMonth() {
        return firstSecondOfTheMonth(LocalDateTime.now());
    }

    /**
     * 获得本月最后一天的最后一秒
     *
     * @return 本月最后一天的最后一秒
     */
    public static LocalDateTime lastSecondOfThisMonth() {
        return lastSecondOfTheMonth(LocalDateTime.now());
    }

    /**
     * 获得今天的第一秒
     *
     * @return 今天的第一秒
     */
    public static LocalDateTime firstSecondOfToday() {
        return firstSecondOfTheDay(LocalDateTime.now());
    }

    /**
     * 获得今天的最后一秒
     *
     * @return 今天的最后一秒
     */
    public static LocalDateTime lastSecondOfToday() {
        return lastSecondOfTheDay(LocalDateTime.now());
    }

    /**
     * 获得timePoint所指定的时间点所在月的最后一天的最后一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在月的最后一天的最后一秒
     */
    public static LocalDateTime lastSecondOfTheMonth(final LocalDateTime timePoint) {
        return firstSecondOfTheMonth(timePoint.plusMonths(1)).minusSeconds(1);
    }


    public static LocalDate firstDateOfTheMonth(final Integer year, final Integer month) {
        return LocalDate.of(year, month, 1);
    }

    /**
     * 获得timePoint所指定的时间点所在年份的第一天的第一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在年份的第一天的第一秒
     */
    public static LocalDateTime firstSecondOfTheYear(final LocalDateTime timePoint) {
        return firstSecondOfTheMonth(timePoint).minusMonths((timePoint.getMonthValue() - 1));
    }

    public static LocalDate firstDateOfTheYear(final Integer year) {
        return LocalDate.of(year, Month.JANUARY, 1);
    }

    /**
     * 获得timePoint所指定的时间点所在季度的第一天的第一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在季度的第一天的第一秒
     */
    public static LocalDateTime firstSecondOfTheQuarter(final LocalDateTime timePoint) {
        Month month = timePoint.getMonth();
        Month firstMonthOfQuarter = month.firstMonthOfQuarter();
        return LocalDateTime.of(timePoint.getYear(), firstMonthOfQuarter, 1, 0, 0, 0);
    }

    /**
     * 获得timePoint所指定的时间点所在季度的最后一天的最后一秒
     *
     * @param timePoint 指定时间点
     * @return 时间点所在季度的最后一天的最后一秒
     */
    public static LocalDateTime lastSecondOfTheQuarter(final LocalDateTime timePoint) {
        Month month = timePoint.getMonth();
        Month firstMonthOfQuarter = month.firstMonthOfQuarter();
        Month endMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
        return lastSecondOfTheMonth(LocalDateTime.of(timePoint.getYear(), endMonthOfQuarter, 1, 23, 59, 59));
    }

    /**
     * 获得timePoint所指定的时间点所在年份的最后一天的最后一秒
     *
     * @param timePoint 时间点
     * @return 时间点所在年份的最后一天的最后一秒
     */
    public static LocalDateTime lastSecondOfTheYear(final LocalDateTime timePoint) {
        return firstSecondOfTheYear(timePoint).plusYears(1).minusSeconds(1);
    }

    /**
     * 取一天的第一秒钟的时间点
     *
     * @param timePoint 时间点
     * @return 一天的第一秒钟的时间点
     */
    public static LocalDateTime firstSecondOfTheDay(final LocalDateTime timePoint) {
        return timePoint.truncatedTo(ChronoUnit.DAYS);
    }

    /**
     * 取一天的最后一秒钟
     *
     * @param timePoint 时间点
     * @return 一天的最后一秒钟
     */
    public static LocalDateTime lastSecondOfTheDay(final LocalDateTime timePoint) {
        return firstSecondOfTheDay(timePoint).plusDays(1).minusSeconds(1);
    }

    /**
     * 返回无限远的时间点
     *
     * @return 无限远的时间点
     */
    public static LocalDateTime infinity() {
        return LocalDateTime.of(2999, 12, 31, 23, 59, 59);
    }

    // 获得当前时刻的Date类型时间
    public static Date getNowDate() {
        return ConvertDateTimeUtils.LocalDateTimeToDate.apply(LocalDateTime.now());
    }

}
